package casa.depesos.app.com.http;

import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.common.base.utils.WeakHandler;
import com.google.gson.Gson;
import com.support.toast.ToastUtil;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

import casa.depesos.app.com.App;
import casa.depesos.app.com.BuildConfig;
import casa.depesos.app.com.http.req.UploadReq;
import casa.depesos.app.com.utils.Constant;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class Req {

    static WeakHandler h = new WeakHandler(Looper.getMainLooper());
    public static final MediaType JSON
            = MediaType.get("application/json");

    static volatile OkHttpClient mClient, uploadClient;

    public static OkHttpClient getClient(HttpReq req) {
        if (req instanceof UploadReq) {
            return getUploadClient();
        }
        if (mClient == null) {
            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(35000, TimeUnit.MILLISECONDS)
                    .readTimeout(35000, TimeUnit.MILLISECONDS)
                    .writeTimeout(35000, TimeUnit.MILLISECONDS);
            if (BuildConfig.DEBUG) {
                builder.hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                });
            }
            mClient = builder.build();
        }
        return mClient;
    }

    public static OkHttpClient getUploadClient() {
        if (uploadClient == null) {
            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(60000, TimeUnit.MILLISECONDS)
                    .readTimeout(60000, TimeUnit.MILLISECONDS)
                    .writeTimeout(60000, TimeUnit.MILLISECONDS);
            if (BuildConfig.DEBUG) {
                builder.hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                });
            }
            uploadClient = builder.build();
        }
        return uploadClient;
    }

    public static <T extends BaseBean> T post(String url, @NonNull Map<String, String> param,
                                              Map<String, String> header, @NonNull Map body,
                                              BaseParser<T> parser, HttpReq req) throws Exception {
        if (Constant.white && !req.pass()) {
            return null;
        }
        Request request = getReqBuilder(url, param, header).post(RequestBody.create(JSON, new Gson().toJson(body))).build();
        Response response = getClient(req).newCall(request).execute();
        String str = response.body().string();
        if (Constant.log) {
            Log.e("network", request.url() + " get " + str);
        }
        return parser.parse(str);
    }

    public static <T extends BaseBean> T post(String url, @NonNull Map<String, String> param,
                                              Map<String, String> header, @NonNull RequestBody body,
                                              BaseParser<T> parser, HttpReq req) throws Exception {
        if (Constant.white && !req.pass()) {
            return null;
        }
        Request request = getReqBuilder(url, param, header).post(body).build();
        Response response = getClient(req).newCall(request).execute();
        String str = response.body().string();
        if (Constant.log) {
            Log.e("network", request.url() + " get " + str);
        }
        return parser.parse(str);
    }

    public static <T extends BaseBean> void post(String url, @NonNull Map<String, String> param, Map<String, String> header,
                                                 RequestBody body, BaseParser<T> parser,
                                                 ReqCallback<T> callback, HttpReq req) {
        Request request = getReqBuilder(url, param, header).post(body).build();
        post(request, parser, callback, req);
    }

    public static <T extends BaseBean> void post(String url, @NonNull Map<String, String> param, Map<String, String> header,
                                                 @NonNull Map<String, String> body, BaseParser<T> parser,
                                                 ReqCallback<T> callback, HttpReq req) {
        Request request = getReqBuilder(url, param, header).post(RequestBody.create(JSON, new Gson().toJson(body))).build();
        post(request, parser, callback, req);
    }

    private static <T extends BaseBean> void post(Request request, BaseParser<T> parser, ReqCallback<T> callback, HttpReq req) {
        if (Constant.white && !req.pass()) {
            h.post(() -> callback(false, null, new RuntimeException("forbidden"), callback));
            return;
        }
        getClient(req).newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                h.post(() -> callback(false, null, e, callback));
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) {
                try {
                    String str = response.body().string();
                    if (Constant.log) {
                        Log.e("network", request.url() + " get " + str);
                    }
                    T bean = parser.parse(str);
                    h.post(() -> callback(true, bean, null, callback));
                } catch (Throwable e) {
                    h.post(() -> callback(false, null, e, callback));
                }
            }
        });
    }

    private static <T extends BaseBean> void callback(boolean success, T bean, Throwable e, ReqCallback<T> callback) {
        if (success) {
            if (bean.isValid()) {
                callback.callback(true, bean);
            } else {
                if (bean.showErrMsg()) {
                    ToastUtil.showLongToast(App.getApp(), bean.msg);
                }
                if (!bean.isTokenExpired()) {
                    callback.callback(false, bean);
                } else {
                    App.getApp().reLog();
                }
            }
        } else {
            e.printStackTrace();
            callback.callback(false, null);
        }
    }

    private static Request.Builder getReqBuilder(String url, @NonNull Map<String, String> param, Map<String, String> header) {
        StringBuffer sb = new StringBuffer();
        url = Http.HOST + url;
        for (String key : param.keySet()) {
            sb.append("&")
                    .append(key)
                    .append("=")
                    .append(URLEncoder.encode(param.get(key)));
        }
        String s = sb.toString();
        if (!TextUtils.isEmpty(s)) {
            s = s.substring(1);
            url += "?" + s;
        }
        Request.Builder builder = new Request.Builder().url(url);
        if (header != null && !header.isEmpty()) {
            for (String key : header.keySet()) {
                String v = header.get(key);
                if (v == null) {
                    continue;
                }
                builder.header(key, header.get(key));
            }
        }
        return builder;
    }

    public static <T extends BaseBean> void get(String url, @NonNull Map<String, String> param, Map<String, String> header,
                                                BaseParser<T> parser, ReqCallback<T> callback, HttpReq req) {
        if (Constant.white && !req.pass()) {
            h.post(() -> callback(false, null, new RuntimeException("forbidden"), callback));
            return;
        }
        getClient(req).newCall(getReqBuilder(url, param, header).get().build()).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                h.post(() -> callback(false, null, e, callback));
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) {
                try {
                    String str = response.body().string();
                    if (Constant.log) {
                        Log.e("network", url + " get " + str);
                    }
                    T bean = parser.parse(str);
                    h.post(() -> callback(true, bean, null, callback));
                } catch (Throwable e) {
                    h.post(() -> callback(false, null, e, callback));
                }
            }
        });
    }

    public static <T extends BaseBean> T get(String url, @NonNull Map<String, String> param,
                                             Map<String, String> header,
                                             BaseParser<T> parser, HttpReq req) throws Exception {
        if (Constant.white && !req.pass()) {
            return null;
        }
        Request request = getReqBuilder(url, param, header).get().build();
        Response response = getClient(req).newCall(request).execute();
        String str = response.body().string();
        if (Constant.log) {
            Log.e("network", request.url() + " get " + str);
        }
        return parser.parse(str);
    }
}
